Win/Linux下操作ini配置文件(API)

 我们的程序常常需要从配置文件中获取参数,一方面,用户关于程序的自定义配置往往就存储在配置文件中,自定义配置的适配与保存就转化为对配置文件的读写操作;另一方面,也是本文编写的由来,那就是将有关程序中核心算法的参数提取到配置文件,方便算法参数的调试(只要调整配置文件,无需修改程序源码,更无需重新构建)。
 .ini 文件作为典型的配置文件,其文件存储的内容基本上是一些参数的 Key-Value 形式,此外就是一些所谓的属性段,多个对同一方面参数进行描述的 键值对 可以归纳为一个 Section
 下面,是 Win/Linux 下如何通过不同的 API 实现对 *.ini 配置文件读写操作的整理。

Linux, using Glib API

Reference:

 Linux 下我们通过使用 Glib API 操作 .ini 文件,具体流程包括安装 Glib 库,加载 ini 文件,通过 Key 读写键值对,最后再卸载文件。

1. Configure Runtime Environment

1
xxx@...$ sudo apt-get install libglib2.0-dev

 Install glib-2.0 and add it as a link library for build option.

2. Create File Handler

APIs:

1
2
3
4
5
6
7
8
9
GKeyFile* g_key_file_new (void);

gboolean g_key_file_load_from_file (GKeyFile *key_file,
const gchar *file,
GKeyFileFlags flags,
GError **error);
flags: G_KEY_FILE_NONE
| G_KEY_FILE_KEEP_COMMENTS
| G_KEY_FILE_KEEP_TRANSLATIONS

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <glib.h>
#include <stdio.h> // for fprintf&stderr
#include <stdlib.h> // for EXIT_FAILURE

// get Gkeyfile
GKeyFile* viewer_ini = g_key_file_new();
GError **error = NULL;

if (!g_key_file_load_from_file(viewer_ini, "velodyne.ini",
G_KEY_FILE_NONE, error)){
fprintf (stderr, "Could not read config file\n");
return EXIT_FAILURE;
}

3. Read/Write Parameters from/to File
 我们选用常用的数据类型,integer, double, string, boolean

APIs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
gint g_key_file_get_integer (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
void g_key_file_set_integer (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gint value);

gdouble g_key_file_get_double (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
void g_key_file_set_double (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gdouble value);

gchar* g_key_file_get_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
void g_key_file_set_string (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
const gchar *string);

gboolean g_key_file_get_boolean (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
GError **error);
void g_key_file_set_boolean (GKeyFile *key_file,
const gchar *group_name,
const gchar *key,
gboolean value);

Examples:

1
2
3
4
5
6
7
# velodyne.ini
[CfgGlobal]
GroundZ=-192
CarLength=469
CarWidth=185
CarHeight=172
Threshold=0.820000

1
2
3
4
5
6
7
8
9
10
// *.cpp
cfg.cfgGlobal.GroundZ =
g_key_file_get_integer(viewer_ini, "CfgGlobal", "GroundZ", error);
cfg.cfgGlobal.ThresholdMinRad =
g_key_file_get_double(viewer_ini, "CfgGlobal", "Threshold", error);

g_key_file_set_integer(viewer_ini, "CfgGlobal", "GroundZ",
cfg.cfgGlobal.GroundZ);
g_key_file_set_double(viewer_ini, "CfgGlobal", "ThresholdMinRad",
cfg.cfgGlobal.Threshold);

4. Free File Handler

API:

1
void g_key_file_free (GKeyFile *key_file);

Example:

1
g_key_file_free (glib_keyfile);

Windows, using Winbase API

 Windows 下我们使用 Winbase.h 提供的 API 操作 .ini 文件,与 Linux 下使用 Glib API 最大的不同是,不存在配置文件的加载,卸载流程,不过每次读写参数时都需要传递操作文件所需要的文件名;此外,支持的数据类型也比较少(似乎就只有 IntString),写操作更是只有 String 数据类型。
 下面是简单功能的基本实现。

APIs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
UINT WINAPI GetPrivateProfileInt(
_In_ LPCTSTR lpAppName,
_In_ LPCTSTR lpKeyName,
_In_ INT nDefault,
_In_ LPCTSTR lpFileName
);
DWORD WINAPI GetPrivateProfileString(
_In_ LPCTSTR lpAppName,
_In_ LPCTSTR lpKeyName,
_In_ LPCTSTR lpDefault,
_Out_ LPTSTR lpReturnedString,
_In_ DWORD nSize,
_In_ LPCTSTR lpFileName
);

BOOL WINAPI WritePrivateProfileString(
_In_ LPCTSTR lpAppName,
_In_ LPCTSTR lpKeyName,
_In_ LPCTSTR lpString,
_In_ LPCTSTR lpFileName
);

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// for GetPrivateProfileInt&Get/WritePrivateProfileString
#include <windows.h>
#include <winbase.h>
// for _snprintf
#include <stdio.h>
// for atof
#include <stdlib.h>

char buf[64];
char defaultVal[64];

cfg.cfgGlobal.GroundZ =
GetPrivateProfileInt("CfgGlobal", "GroundZ", g_DefaultGlobalCfg.GroundZ, "velodyne.ini");

_snprintf(defaultVal, sizeof(defaultVal), "%f", g_DefaultGlobalCfg.Threshold);
GetPrivateProfileString("CfgGlobal", "Threshold", defaultVal, buf, sizeof(buf), "velodyne.ini");
cfg.cfgGlobal.Threshold = (double)atof(buf);


char val[64];
_snprintf(val, sizeof(val), "%d", cfg.cfgGlobal.GroundZ);
WritePrivateProfileString("CfgGlobal", "GroundZ", val, "velodyne.ini");

_snprintf(val, sizeof(val), "%.6f", cfg.cfgGlobal.Threshold);
WritePrivateProfileString("CfgGlobal", "Threshold", val, "velodyne.ini");

注意:

  • GetPrivateProfileInt 和 GetPrivateProfileString 都需要传递缺省值,而且每一次都需要制定对应的配置文件;假如成功找到对应的参数键,返回对应的值,否则返回传进去的缺省值。
  • 对于 IntString 除外的数据类型,通过 GetPrivateProfileString 获取参数键对应的值,不过返回的值是参数值对应的字符串,需要再通过 atofatoiatol 转为对应的数据类型。
  • 关于键值对保存到配置文件,只有 WritePrivateProfileString 这种字符串数据类型,需要通过 _snprintf 将要保存的参数数据类型转为字符串格式再进行保存。 _snprintf 的格式说明和 printf 基本相同。
文章目录
  1. 1. Linux, using Glib API
  2. 2. Windows, using Winbase API